package com.wwj.server.game;

import com.google.gson.Gson;
import com.wwj.core.log.entity.LogGame;
import com.wwj.core.log.service.ILogGameService;
import com.wwj.core.wawa.entity.PlayRecord;
import com.wwj.core.wawa.entity.Player;
import com.wwj.core.wawa.entity.WaWaMachine;
import com.wwj.core.wawa.service.IPlayRecordService;
import com.wwj.core.wawa.service.IPlayerService;
import com.wwj.core.wawa.service.IWaWaMachineService;
import com.wwj.server.game.common.CmdConstants;
import com.wwj.server.game.common.ExtraConstants;
import com.wwj.server.game.common.MsgConstants;
import com.wwj.server.game.msg.*;
import com.wwj.server.game.session.SessionManager;
import com.wwj.server.game.utils.SpringContextUtils;
import com.wwj.server.model.Message;
import com.wwj.server.session.Session;
import com.wwj.server.utils.ExtraUtil;
import com.wwj.server.utils.NettySocketUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.Map;

/**
 * 消息接受处理类
 *
 * @author tysci
 */
public class ClientHandler extends SimpleChannelInboundHandler<Message> {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private ILogGameService logGameService = (ILogGameService) SpringContextUtils.getContext().getBean("logGameServiceImpl");

    private JedisPool jedisPool = (JedisPool) SpringContextUtils.getContext().getBean("jedisPool");

    private IPlayerService playerService = (IPlayerService) SpringContextUtils.getContext().getBean("playerServiceImpl");

    private IPlayRecordService playRecordService = (IPlayRecordService) SpringContextUtils.getContext().getBean("playRecordServiceImpl");

    private IWaWaMachineService waWaMachineService = (IWaWaMachineService) SpringContextUtils.getContext().getBean("waWaMachineServiceImpl");


    //1.连接注册
    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        super.channelRegistered(ctx);
        //logger.debug("host:{} 开始连接本机...", NettySocketUtil.getHostName(ctx));
    }

    //2.连接激活
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        //logger.debug("host:{} 连接通道已激活...", NettySocketUtil.getHostName(ctx));
    }

    /**
     * 接收消息
     */
    //3.数据读取
    @Override
    public void channelRead0(ChannelHandlerContext ctx, Message message) throws Exception {
        //消息分类
        //1.control --> game 注册绑定回调
        //2.control --> game 移动端控制回调
        //3.control --> game 娃娃抓取结果
        //logger.debug("host:{} 开始接收消息...", NettySocketUtil.getHostName(ctx));
        //logger.debug("消息内容：" + new String(message.getData()));
        handlerMessage(message);
    }

    //4.数据读取完毕
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        super.channelReadComplete(ctx);
        //logger.debug("host:{} 消息接收完毕...", NettySocketUtil.getHostName(ctx));
    }


    /**
     * 断线移除会话
     */
    //5.连接无效
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        logger.debug("host:{} 远程连接已失效...", NettySocketUtil.getHostName(ctx));
        logger.debug("开始尝试重新进行连接...", NettySocketUtil.getHostName(ctx));
        Main.client.setRegister(false);
        Main.client.rebind();
    }

    //6.连接注销
    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        super.channelUnregistered(ctx);
        //logger.debug("host:{} 远程连接已注销...", NettySocketUtil.getHostName(ctx));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        Channel channel = ctx.channel();
        if (!channel.isActive()) {
            logger.info("#######################--服务端-{}断开了长连接！", channel.remoteAddress());
            ctx.close();
        } else {
            ctx.fireExceptionCaught(cause);
            logger.error("#######################", cause);
        }
    }

    /**
     * 消息处理
     *
     * @param message
     */
    private void handlerMessage(Message message) {

        String sessionKey = null;
        Session session = null;
        switch (message.getType()) {
            //game注册绑定到control后的回调
            case MsgConstants.GAME_SERVER_BIND_ACK:
                logger.debug("GET Message「ControlServer」:" + new String(message.getData()));
                GameServerBindMsgAck gameServerBindMsgAck = new Gson().fromJson(new String(message.getData()), GameServerBindMsgAck.class);
                if (gameServerBindMsgAck.getResult().toUpperCase().equals("Y")) {
                    Main.client.setRegister(true);
                } else {
                    logger.warn("GameServer <--> ControlServer 远程连接失败！");
                }
                break;
            //control反馈控制结果
            case MsgConstants.GAME_SERVER_CMD_ACK:
                logger.debug("GET Message「ControlServer」:" + new String(message.getData()));
                GameServerCmdMsgAck gameServerCmdMsgAck = new Gson().fromJson(new String(message.getData()), GameServerCmdMsgAck.class);
                sessionKey = SessionManager.PREFIX_SESSION_KEY_USER + gameServerCmdMsgAck.getUserId();
                SessionManager.sendMessage(sessionKey, new UserCmdMsgAck(gameServerCmdMsgAck));
                if (gameServerCmdMsgAck.getCmd().equals(CmdConstants.DEVICE_CMD_COIN)
                        && gameServerCmdMsgAck.getResult().toUpperCase().equals("Y")) {
                    //反馈投币指令成功，开始倒计时
                    LogGame log = new LogGame(gameServerCmdMsgAck.getKey(), Main.client.getServerName(), Integer.parseInt(gameServerCmdMsgAck.getUserId()), gameServerCmdMsgAck.getDeviceId());
                    try {
                        logGameService.createNewLog(log);
                    } catch (Exception e) {
                        logger.error("生成游戏日志：", e);
                    }
                } else if (gameServerCmdMsgAck.getCmd().equals(CmdConstants.DEVICE_CMD_CATCH)
                        && gameServerCmdMsgAck.getResult().toUpperCase().equals("Y")) {
                    //反馈抓取指令成功
                    LogGame log = new LogGame();
                    log.setKey(gameServerCmdMsgAck.getKey());
                    log.setCatchTime(Long.toString(System.currentTimeMillis()));
                    if (gameServerCmdMsgAck.getExtra() != null && !"".equals(gameServerCmdMsgAck.getExtra())) {
                        Map<String, String> extraMap = ExtraUtil.getExtraData(gameServerCmdMsgAck.getExtra());
                        if (extraMap != null && extraMap.size() > 0) {
                            String isAutoCatch = extraMap.get(ExtraConstants.EXTRA_IS_AUTO_CATCH);
                            if (isAutoCatch != null && isAutoCatch.equals("1")) {
                                log.setCatchType(LogGame.CATCH_TYPE_AUTO);
                            } else if (isAutoCatch != null && isAutoCatch.equals("0")) {
                                log.setCatchType(LogGame.CATCH_TYPE_MANUAL);
                            }
                        }
                    }
                    try {
                        logGameService.updateLog(log);
                    } catch (Exception e) {
                        logger.error("修改游戏日志：", e);
                    }
                }
                break;
            //control反馈娃娃抓取结果
            case MsgConstants.GAME_SERVER_GAME_RESULT:
                logger.debug("GET Message「ControlServer」:" + new String(message.getData()));
                GameServerGameResultMsg gameServerGameResultMsg = new Gson().fromJson(new String(message.getData()), GameServerGameResultMsg.class);
                sessionKey = SessionManager.PREFIX_SESSION_KEY_USER + gameServerGameResultMsg.getUserId();
                Player player = null;
                if (SessionManager.isOnline(sessionKey)) {//session在线
                    session = SessionManager.getSession(sessionKey);
                    if (session != null) {
                        Object object = session.getAttachment();
                        if (object instanceof Player) {
                            player = (Player) object;
                            final String userSessionKey = sessionKey;
                            final String deviceId = gameServerGameResultMsg.getDeviceId();
                            final String userId = gameServerGameResultMsg.getUserId();
                            final String key = gameServerGameResultMsg.getKey();
                            Thread coinTimeOutThread = new Thread(new Runnable() {
                                @Override
                                public void run() {
                                    try {
                                        Thread.sleep(12000);
                                        logger.debug("12s 超时线程调用, userId={}, deviceId={}, sessionKey={}, key={}",userId,deviceId, userSessionKey, key);
                                        Session session = SessionManager.getSession(userSessionKey);
                                        Player player = null;
                                        if (null != session) {
                                            Object object = session.getAttachment();
                                            if (object instanceof Player) {
                                                player = (Player) object;
                                            }
                                        } else {
                                            player = playerService.findById(Integer.parseInt(userId));
                                        }

                                        if(null == player)
                                            return;

                                        try {
                                            WaWaMachine machine = waWaMachineService.findByDeviceId(deviceId);
                                            if (null != machine && machine.getStatus() == WaWaMachine.STATUS_PROGRESS
                                                    && null != machine.getCurrentKey() && machine.getCurrentKey().equals(key) ) {
                                                machine.setStatus(WaWaMachine.STATUS_IDLE);
                                                machine.setCurrentPlayerId(null);
                                                machine.setCurrentKey(null);
                                                waWaMachineService.updateMachine(machine);
                                                //推送下机信息至队列
                                                pushGameOverToNotify(player, deviceId);
                                            }
                                        } catch (Exception e) {
                                            logger.error("超时线程关闭用户娃娃机占用", e);
                                        }
                                        SessionManager.sendMessage(userSessionKey, new UserDisconnectMsgAck(player.getId().toString(), key, "Y"));
                                        SessionManager.removeSession(userSessionKey);
                                        if (null != session)
                                            session.close();
                                    } catch (InterruptedException e) {
                                        logger.debug("sessionKey={},超时线程终止.",userSessionKey);
                                    }
                                }
                            });
                            player.setCoinTimeOutThread(coinTimeOutThread);
                            coinTimeOutThread.start();
                        }
                    }

                    SessionManager.sendMessage(sessionKey, new UserGameResultMsg(gameServerGameResultMsg));
                }else{
                    try {
                        WaWaMachine machine = waWaMachineService.findByDeviceId(gameServerGameResultMsg.getDeviceId());
                        player = playerService.findById(Integer.parseInt(gameServerGameResultMsg.getUserId()));
//                        if (null != machine && machine.getStatus() == WaWaMachine.STATUS_PROGRESS) {
                        if (null != machine && machine.getStatus() == WaWaMachine.STATUS_PROGRESS
                                && null != machine.getCurrentKey() && machine.getCurrentKey().equals(gameServerGameResultMsg.getKey()) ) {
                            machine.setStatus(WaWaMachine.STATUS_IDLE);
                            machine.setCurrentPlayerId(null);
                            machine.setCurrentKey(null);
                            waWaMachineService.updateMachine(machine);
                            pushGameOverToNotify(player, gameServerGameResultMsg.getDeviceId());
                        }
                    } catch (Exception e) {
                        logger.error("玩家断开session更新娃娃机状态异常:",e);
                    }

                }

                try {
                    //更新player和playRecord信息
                    PlayRecord record = playRecordService.findByToken(gameServerGameResultMsg.getKey());
                    if (null != record) {
                        record.setPlayResult(gameServerGameResultMsg.getResult().toUpperCase().equals("Y") ? PlayRecord.RESULT_SUCCESS : PlayRecord.RESULT_FAILED);
                        //playRecordService.updatePlayRecord(record);
                        playRecordService.updatePlayRecordForResult(player, record);
                    }
                } catch (Exception e) {
                    logger.error("反馈抓取结果，修改player和record记录");
                }

                //修改日志表抓取记录
                LogGame log = new LogGame();
                log.setKey(gameServerGameResultMsg.getKey());
                log.setCatchResult(gameServerGameResultMsg.getResult());
                try {
                    logGameService.updateLog(log);
                } catch (Exception e) {
                    logger.error("修改游戏日志：", e);
                }

                break;
            case MsgConstants.GAME_SERVER_HEARTBEAT_ACK:
                break;
            default:
                logger.error("type not exists");
        }

    }

    private void pushGameOverToNotify(Player player, String deviceId) {
        Jedis jedis = jedisPool.getResource();
        JSONObject jsonObj = new JSONObject();
        jsonObj.put("device_id", deviceId);
        jsonObj.put("user_id",player.getId());
        jsonObj.put("nickname", player.getNickname());
        jsonObj.put("header_icon",player.getHeaderIcon());
        jedis.lpush("leave-queue", jsonObj.toString());
        jedis.close();
        logger.debug("推送消息至redis:{}",jsonObj.toString());
    }

}
